/*
 * ============================================================================
 *
 *       Filename:  packet_capture.c
 *
 *    Description:  
 *
 *        Version:  1.0
 *        Created:  2025年03月17日 18时38分39秒
 *       Revision:  none
 *       Compiler:  gcc
 *
 *         Author:  xiaojian jiang (Adams), <yunsangc@163.com>
 *   Organization:  
 *
 * ============================================================================
 */
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <time.h>
#include <dirent.h>
#include <jansson.h>

#include "log.h"
#include "list.h"
#include "cJSON.h"
#include "common.h"
#include "config.h"
#include "packet_capture.h"
#include "socket_connect.h"

PCAP_Run_state pcap_write = IDEL; // 当前是否在写文件

uint64_t pcap_pkg_count = 0;  // 本次已写入文件的包的总数量
uint64_t pcap_pkg_size = 0;   // 本次已写入文件的包的总大小
time_t write_start_time = 0;  // 开启写入文件的时间戳

pthread_mutex_t pcap_file_write_lock;
pcap_file_t *pcap_file_write = NULL;
pcap_file_t *pcap_file_write_new = NULL;
int change_new = NEW_NO;

int pcap_file_write_lock_init()
{
        return pthread_mutex_init(&pcap_file_write_lock, NULL);
}

packet_capture_t *pkgcap_ctx = NULL;
packet_capture_t *get_pkgcap_ctx()
{
	return pkgcap_ctx;
}
uint64_t single_file_max_size;
void set_single_file_max_size(int _size_MB)
{
	single_file_max_size = (_size_MB > 0)?(_size_MB * MB):(100 * MB);
}

/* 根据 信息打开文件并更新file */
int compose_open_file(packet_capture_t *pkgcap_in)
{
	if (!pkgcap_in) {
		return -1;
	}
	if (pkgcap_in->change_file) {
		sys_debug("anoter change running!");
		return -2;
	}
	pkgcap_in->change_file = 1;

	char file_path[256] = {0};
	char file_tmp_path[256] = {0};
	uint32_t num = pkgcap_in->files_count + 1;

	snprintf(file_path, 256, "%s/%s_%u.pcap", pkgcap_in->task_dir, pkgcap_in->wid, num);
	snprintf(file_tmp_path, 256, "%s/.%s_%u.pcap", pkgcap_in->task_dir, pkgcap_in->wid, num);

	pcap_dumper_t *file = pcap_dump_open(pkgcap_in->handler, file_tmp_path);
	if (!file) {
		pkgcap_in->change_file = 0;
		return -1;
	}
	Lzlog_debug("change save new file:%s\n", file_path);
	//创建新的文件存储对象并放在链表中，然后更新读写链接
	pcap_file_t *pcap_file_point = ss_malloc(sizeof(pcap_file_t));
	pcap_file_point->file_path = strdup(file_path);
	pcap_file_point->file_path_tmp = strdup(file_tmp_path);
	pcap_file_point->file = file;

	pkgcap_in->file_path = pcap_file_point->file_path;
	pkgcap_in->file_path_tmp = pcap_file_point->file_path_tmp;
	pkgcap_in->file = pcap_file_point->file;
	list_add_tail(&pcap_file_point->node, &pkgcap_in->files_list);
	pkgcap_in->files_count++;

        pthread_mutex_lock(&pcap_file_write_lock);
	pcap_file_write_new = pcap_file_point;

        pthread_mutex_unlock(&pcap_file_write_lock);
	pkgcap_in->change_file = 0;
	return 0;
}

/* 抓包cb */
void packet_handler_cb(u_char *param, const struct pcap_pkthdr *header, const u_char *pkt_data)
{
	/* 向第三方服务器发送 TCP 数据 */
	send_data_by_tcp(pkt_data, header->len);

	if (FILE_WRITING != pcap_write) {
		if (FILE_RADY == pcap_write) {
			pcap_pkg_count = 0;
			pcap_pkg_size = 0;
			pcap_write = FILE_WRITING;
		} else {
			return;
		}
	}
	if (change_new == NEW_YES) {
		change_new = NEW_NO;
                pthread_mutex_lock(&pcap_file_write_lock);

		if (pcap_file_write && pcap_file_write->file) {
			pcap_dump_close(pcap_file_write->file);
			rename(pcap_file_write->file_path_tmp, pcap_file_write->file_path);
		}
		pcap_file_write = pcap_file_write_new;
                pcap_file_write_new = NULL;

                pthread_mutex_unlock(&pcap_file_write_lock);
	}

        pthread_mutex_lock(&pcap_file_write_lock);
	if (pcap_file_write && pcap_file_write->file) {
		pcap_dump((u_char *)(pcap_file_write->file), header, pkt_data);

		pcap_file_write->count++;
		pcap_file_write->size += header->len;
		pcap_pkg_count++;
		pcap_pkg_size += header->len;
		if (pcap_file_write->size > single_file_max_size) {
                        sys_debug("file %s size is [%lu](MAX:%lu), need cread new file to save.\n",
                                pcap_file_write->file_path,pcap_file_write->size , single_file_max_size);
                        Lzlog_debug("file %s size is [%lu](MAX:%lu), need cread new file to save.",
                                pcap_file_write->file_path,pcap_file_write->size , single_file_max_size);
                        pthread_mutex_unlock(&pcap_file_write_lock);
			if (!compose_open_file(get_pkgcap_ctx())) {
				change_new = NEW_YES;
			}
                        return;
		}
	}
        pthread_mutex_unlock(&pcap_file_write_lock);
}

/* 打开网络设备 */
pcap_t *open_netdevice_package_capture(const char *net_device)
{
	char pcap_errstr[PCAP_ERRBUF_SIZE] = {0};
	pcap_t *handler = pcap_open_live(net_device, 65536, PCAP_OPENFLAG_PROMISCUOUS , 0, pcap_errstr);
	if (!handler) {
		sys_err("Open network device %s failed\n", pcap_errstr);
		Lzlog_error("Open network device %s failed!", pcap_errstr);
	}
	return handler;
}

/* 创建 */
packet_capture_t *new_packet_capture(const char *net_device)
{
	pcap_t *handler = open_netdevice_package_capture(net_device);
	if (NULL == handler) {
		return NULL;
	}
	packet_capture_t* pkg_cap_ctx = ss_malloc(sizeof(packet_capture_t));
	pkg_cap_ctx->handler = handler;
	pkgcap_ctx = pkg_cap_ctx;

	pcap_write = IDEL;

	return pkg_cap_ctx;
}
/* 删除list */
void destroy_file_list(struct list_head *_head)
{
	if (list_empty(_head)) {
		return;
	}
	pcap_file_t *pos = NULL, *n = NULL;
	list_for_each_entry_safe(pos, n, _head, node) {
		list_del(&pos->node);
                if (pos->file_path)
		        ss_free(pos->file_path);
                if (pos->file_path_tmp)
		        ss_free(pos->file_path_tmp);
		ss_free(pos);
	}
}

/* 删除并释放malloc packet_capture_t */
void destroy_packet_capture(packet_capture_t *_del)
{
	if (_del)
		return;
	Lzlog_debug("destroy packet capture");
	pcap_close(_del->handler);

        if (_del->write_dir)
	        ss_free(_del->write_dir);
        if (_del->file_path)
	        ss_free(_del->file_path);
        if (_del->file_path_tmp)
	        ss_free(_del->file_path_tmp);
        if (_del->wid)
	        ss_free(_del->wid);
        if (_del->task_dir)
	        ss_free(_del->task_dir);

	ss_free(_del);
	destroy_file_list(&_del->files_list);
	return;
}


/* 遍历文件夹中的pcap文件并添加到列表中 */
void traversal_pcap_directory_add_list(packet_capture_t *pkgcap_ctx)
{
	if (!pkgcap_ctx || !pkgcap_ctx->task_dir) {
		return;
	}
	char *dir_path = pkgcap_ctx->task_dir;
	struct list_head *_head = &pkgcap_ctx->files_list;
	DIR *dirp = opendir(dir_path);
	if (!dirp) {
		sys_debug("Open dir %s failed!%d(%s)\n", dir_path, errno, strerror(errno));
		return;
	}
	struct dirent *dir = NULL;
	uint32_t file_count = 0;
	char file_path[300] = {0};
	while ((dir = readdir(dirp)) != NULL) {
		if (!strstr(dir->d_name, "pcap")) {
			continue;
		}
		snprintf(file_path, 300, "%s/%s", dir_path, dir->d_name);
		pcap_file_t *pcap_file_point = ss_malloc(sizeof(pcap_file_t));
		if (pcap_file_point) {
			pcap_file_point->file_path = strdup(file_path);
			pcap_file_point->size = dir->d_reclen;
			list_add_tail(&pcap_file_point->node, _head);
			file_count++;
		}
	} /* End while (readdir())*/
	pkgcap_ctx->files_count = file_count;
	closedir(dirp);
}

/* 解析并设置抓包动作 */
void control_start_stop_write_file(const char *commond_str, packet_capture_t *pkgcap_ctx)
{
	if (!commond_str) {
		return;
	}
	int ret = -1;
	char *cmd_op = NULL;
	cJSON *res_root = cJSON_CreateObject();
	char tmp_str[40] = {0};
	// 解析JSON 命令字符串
	cJSON *root = cJSON_Parse(commond_str);
	if (!root) {
		sys_debug("Load commond string failed!%s\n", strerror(errno));
		Lzlog_error("Load commond string'%s' failed!%s", commond_str, strerror(errno));
		if (res_root) {
			cJSON_AddStringToObject(res_root, "result", "-1");
			cJSON_AddStringToObject(res_root, "desc", "Parse cmd string to JSON failed!");
		} /* End if (res_root) */
		goto res_return;
	}
	// 获取op字段内容 即 命令内容
	cJSON *obj_op = cJSON_GetObjectItem(root, "op");
	if (!obj_op || obj_op->type != cJSON_String) {
		sys_debug("Get key 'op' in commond failed!\n");
		Lzlog_debug("Get key 'op' in commond failed!");
		if (res_root) {
			cJSON_AddStringToObject(res_root, "result", "-1");
			cJSON_AddStringToObject(res_root, "desc", "Done not get key [op] in cmd!");
		} /* End if (res_root) */
		goto res_return;
	}
	cmd_op = obj_op->valuestring;
	// 获取 任务id信息
	cJSON *obj_wid = cJSON_GetObjectItem(root, "id");

	// 获取 time信息
	cJSON *obi_time = cJSON_GetObjectItem(root, "time"); // "time":"2025_04_01_15_21_39" 年_月_日_时_分_秒
							     //cJSON *obi_timestamp = cJSON_GetObjectItem(root, "timestamp"); //时间戳
	if (!strcmp(cmd_op, "start")) {/* eg: {"op":"start", "id":"xxxxxxxx", "timestamp":"xxxxxx"} ============================ */
		sys_debug("Get start commond!\n");
		Lzlog_debug("Get start commond!");
		if (!obj_wid || obj_wid->type != cJSON_String) {
			sys_debug("Get key 'task id' in commond failed!\n");
			Lzlog_debug("Get key 'task id' in commond failed!");
			if (res_root) {
				cJSON_AddStringToObject(res_root, "result", "-1");
				cJSON_AddStringToObject(res_root, "desc", "Failed, please set key[id]!");
			} /* End if (res_root) */
			goto res_return;
		}
		/* 开始写文件 */
		if (pcap_write != IDEL && pcap_write != FILE_WRIT_END) {
			sys_debug("pcap is writting! Do nothing!\n");
			Lzlog_debug("pcap is writting! Do nothing!");
			if (res_root) {
				cJSON_AddStringToObject(res_root, "result", "-1");
				cJSON_AddStringToObject(res_root, "desc", "Start failed, another package capture is performed!");
			} /* End if (res_root) */
			goto res_return;
		}
		if (!obi_time || obi_time->type != cJSON_String) {
			sys_debug("Get key 'time' in commond failed!\n");
			Lzlog_debug("Get key 'time' in commond failed!");
			if (res_root) {
				cJSON_AddStringToObject(res_root, "result", "-1");
				cJSON_AddStringToObject(res_root, "desc", "Start failed, please set key[time]!");
			} /* End if (res_root) */
			goto res_return;
		}
		pcap_write = FILE_OPENNING;
		write_start_time = time(NULL);
		char *id = obj_wid->valuestring;
		char task_dir[256] = {0};
		snprintf(task_dir, 256, "%s/%s_%d_%s", pkgcap_ctx->write_dir, id, pkgcap_ctx->vlanid, obi_time->valuestring);

		pkgcap_ctx->wid = strdup(obj_wid->valuestring);
		pkgcap_ctx->task_dir = strdup(task_dir);

		ret = create_dir_recursive(pkgcap_ctx->task_dir); /* 创建目录 */
		if (ret < 0) {//创建目录失败
			Lzlog_error("creat Task directory %s failed!", pkgcap_ctx->task_dir);
			if (res_root) {
				cJSON_AddStringToObject(res_root, "result", "-1");
				cJSON_AddStringToObject(res_root, "task_dir", pkgcap_ctx->task_dir);
				cJSON_AddStringToObject(res_root, "desc", "Start failed, creat task directory failed!");
			} /* End if (res_root) */
			pcap_write = IDEL;
			goto res_return;
		}
		if (ret == 1) { //文件已经存在，说明是需要继续任务,提前将已存在的文件添加进去
			traversal_pcap_directory_add_list(pkgcap_ctx);
		}
		ret = compose_open_file(pkgcap_ctx);
		if (ret == -1) {
			Lzlog_error("pcap open Task file in %s failed!", pkgcap_ctx->task_dir);
			if (res_root) {
				cJSON_AddStringToObject(res_root, "result", "-1");
				cJSON_AddStringToObject(res_root, "file", pkgcap_ctx->file_path);
				cJSON_AddStringToObject(res_root, "desc", "Start failed, open file in task directory failed!");
			} /* End if (res_root) */
			pcap_write = IDEL;
			goto res_return;
		}
		change_new = NEW_YES;
		sys_debug("Start to open and write pcap file:%s\n", pkgcap_ctx->file_path);
		Lzlog_debug("Start to open and write pcap file:%s\n", pkgcap_ctx->file_path);
		pcap_write = FILE_RADY;
		if (res_root) {
			cJSON_AddStringToObject(res_root, "result", "0");
			cJSON_AddStringToObject(res_root, "task_dir", pkgcap_ctx->task_dir);
			cJSON_AddStringToObject(res_root, "desc", "Start OK!");
		} /* End if (res_root) */
	} else if (!strcmp(cmd_op, "forward")) { /* eg: {"op":"forward", "ipaddr":"192.168.1.111", "port":"10086"} ============= */
		cJSON *obj_cmd = cJSON_GetObjectItem(root, "cmd");
		if (!obj_cmd) {
			if (res_root) {
				cJSON_AddStringToObject(res_root, "result", "-1");
				cJSON_AddStringToObject(res_root, "desc", "unknow forward cmd!");
			} /* End if (res_root) */
			goto res_return;
		} /* End if (!obj_cmd) */

		if (!strcmp(obj_cmd->valuestring, "start")) { /* {..."cmd":"start"...} */
			cJSON *obj_ip = cJSON_GetObjectItem(root, "forward_ip");
			cJSON *obj_port = cJSON_GetObjectItem(root, "forward_port");
			if (!obj_ip || obj_ip->type != cJSON_String || strlen(obj_ip->valuestring) < 7) {
				if (res_root) {
					cJSON_AddStringToObject(res_root, "result", "-1");
					cJSON_AddStringToObject(res_root, "desc", "check ipaddr failed!");
				} /* End if (res_root) */
				goto res_return;
			}
			int forward_port = 0;
			if (!obj_port || obj_port->type != cJSON_String || (forward_port = atoi(obj_port->valuestring)) <= 0) {
				if (res_root) {
					cJSON_AddStringToObject(res_root, "result", "-1");
					cJSON_AddStringToObject(res_root, "desc", "check port failed!");
				} /* End if (res_root) */
				goto res_return;
			}
			char *forward_ip = obj_ip->valuestring;
			ret = socket_client_init(forward_ip, forward_port);

			if (ret < 0) {
				if (res_root) {
					cJSON_AddStringToObject(res_root, "result", "-1");
					if (ret == -2) {
						cJSON_AddStringToObject(res_root, "desc", "Forward is running!");
					} else {
						cJSON_AddStringToObject(res_root, "desc", "creat tcp client and connect error!");
					}
				} /* End if (res_root) */
				goto res_return;
			} else {
				if (res_root) {
					cJSON_AddStringToObject(res_root, "result", "0");
					cJSON_AddStringToObject(res_root, "desc", "Set TCP socket forward config success!");
				} /* End if (res_root) */
			}
			/* End cmd is start*/
		} else if (!strcmp(obj_cmd->valuestring, "stop")) { /* {..."cmd":"stop"...} */
			client_ctx_t *ctx = get_client_ctx();
			if (ctx->connect_stat == NO_CONNECT) {
				if (res_root) {
					cJSON_AddStringToObject(res_root, "result", "-1");
					cJSON_AddStringToObject(res_root, "desc", "Forward Stop failed, Forward has not started!");
				} /* End if (res_root) */
				goto res_return;
			}

			if (res_root) {
				cJSON_AddStringToObject(res_root, "forward_ip", ctx->ipaddr);
				snprintf(tmp_str, 40, "%d", ctx->port);
				cJSON_AddStringToObject(res_root, "forward_port", tmp_str); //转发 端口号
				snprintf(tmp_str, 40, "%lu", ctx->count);
				cJSON_AddStringToObject(res_root, "forward_count", tmp_str);
				snprintf(tmp_str, 40, "%lu", ctx->size);
				cJSON_AddStringToObject(res_root, "forward_size", tmp_str);
				cJSON_AddStringToObject(res_root, "result", "0");
				cJSON_AddStringToObject(res_root, "desc", "forward stop OK");
			} /* End if (res_root) */
			client_ctx_stop();
			/* End cmd is stop */
		} else { /* unknow cmd */
			if (res_root) {
				cJSON_AddStringToObject(res_root, "result", "-1");
				cJSON_AddStringToObject(res_root, "desc", "unknow forward cmd!");
			} /* End if (res_root) */
			goto res_return;
		}
	} else if (!strcmp(cmd_op, "stop")) { /* eg: {"op":"stop"} ============================================================= */
		if (pcap_write != FILE_OPENNING &&
			pcap_write != FILE_RADY &&
			pcap_write != FILE_WRITING) {
			if (res_root) {
				cJSON_AddStringToObject(res_root, "result", "-1");
				cJSON_AddStringToObject(res_root, "desc", "Stop failed, package capture has not started!");
			} /* End if (res_root) */
			goto res_return;
		}
		sys_debug("Get stop commond! stop write and close pcap file:%s, Now:state:%d\n", pkgcap_ctx->file_path, pcap_write);
		Lzlog_debug("Get stop commond! stop write and close pcap file:%s, Now:state:%d", pkgcap_ctx->file_path, pcap_write);
		/* 结束写文件 */
		pcap_write = FILE_WRIT_END;
                pthread_mutex_lock(&pcap_file_write_lock);
                pcap_file_write = NULL;
                pcap_file_write_new = NULL;
		pcap_dump_close(pkgcap_ctx->file);
		rename(pkgcap_ctx->file_path_tmp, pkgcap_ctx->file_path);
		if (res_root) {
			cJSON_AddStringToObject(res_root, "task_dir", pkgcap_ctx->task_dir);
			snprintf(tmp_str, 40, "%lu", time(NULL) - write_start_time);
			cJSON_AddStringToObject(res_root, "duration", tmp_str);
			snprintf(tmp_str, 40, "%lu", pcap_pkg_count);
			cJSON_AddStringToObject(res_root, "count", tmp_str);
			snprintf(tmp_str, 40, "%lu", pcap_pkg_size);
			cJSON_AddStringToObject(res_root, "size", tmp_str);
			cJSON_AddStringToObject(res_root, "result", "0");
			cJSON_AddStringToObject(res_root, "desc", "stop OK");
			if (!list_empty(&pkgcap_ctx->files_list) && pkgcap_ctx->files_count > 0) {
				snprintf(tmp_str, 40, "%u", pkgcap_ctx->files_count);
				cJSON_AddStringToObject(res_root, "file_count", tmp_str);
				cJSON *Array = cJSON_CreateArray();
				pcap_file_t *pos, *n;
				list_for_each_entry_safe(pos, n, &pkgcap_ctx->files_list, node) {
					cJSON_AddItemToArray(Array, cJSON_CreateString(pos->file_path));
				}
				cJSON_AddItemToObject(res_root, "files", Array);

                                destroy_file_list(&pkgcap_ctx->files_list);//删除file list
                                pkgcap_ctx->files_count = 0;
			}
		} /* End if (res_root) */

		pcap_pkg_count = 0;
		pcap_pkg_size = 0;
                if (pkgcap_ctx->wid)
		        ss_free(pkgcap_ctx->wid);
                if (pkgcap_ctx->task_dir)
		        ss_free(pkgcap_ctx->task_dir);
                pthread_mutex_unlock(&pcap_file_write_lock);
		pcap_write = IDEL;
	} else if (!strcmp(cmd_op, "query") || !strcmp(cmd_op, "state")) { /* eg: {"op":"query"} =============================== */
		sys_debug("Get state commond! [cmd:%s]\n", cmd_op);
		Lzlog_debug("Get state commond!");
		if (res_root) {
			cJSON_AddStringToObject(res_root, "result", "0");
			switch (pcap_write) {
			case FILE_OPENNING:
			case FILE_RADY:
			case FILE_WRITING:
				{
					cJSON_AddStringToObject(res_root, "desc", "package capture is performed.");
					snprintf(tmp_str, 40, "%lu", time(NULL) - write_start_time);
					cJSON_AddStringToObject(res_root, "duration", tmp_str);
					snprintf(tmp_str, 40, "%lu", pcap_pkg_count);
					cJSON_AddStringToObject(res_root, "count", tmp_str);
					snprintf(tmp_str, 40, "%lu", pcap_pkg_size);
					cJSON_AddStringToObject(res_root, "size", tmp_str);
					cJSON_AddStringToObject(res_root, "status", "2"); // 状态 work
					if (!list_empty(&pkgcap_ctx->files_list) && pkgcap_ctx->files_count > 0) {
						snprintf(tmp_str, 40, "%u", pkgcap_ctx->files_count);
						cJSON_AddStringToObject(res_root, "file_count", tmp_str);
						cJSON *Array = cJSON_CreateArray();
						pcap_file_t *pos, *n;
						list_for_each_entry_safe(pos, n, &pkgcap_ctx->files_list, node) {
							cJSON_AddItemToArray(Array, cJSON_CreateString(pos->file_path));
						}
						cJSON_AddItemToObject(res_root, "files", Array);
					}
				}
				break;
			case IDEL:
			case FILE_WRIT_END:
			default:
				{
					cJSON_AddStringToObject(res_root, "status", "1"); //状态  空闲
					cJSON_AddStringToObject(res_root, "desc", "package capture has not started.");
                                        cJSON_AddStringToObject(res_root, "duration", "0");
					cJSON_AddStringToObject(res_root, "count", "0");
					cJSON_AddStringToObject(res_root, "size", "0");
				}
				break;
			} /* End switch */
			const client_ctx_t *ctx = get_client_ctx();
			if (ctx->connect_stat == NO_CONNECT) {
				cJSON_AddStringToObject(res_root, "forward_status", "1"); //状态  空闲
			} else {
				cJSON_AddStringToObject(res_root, "forward_status", "2"); //状态 work
			}
                        if (ctx->ipaddr && strlen(ctx->ipaddr) > 0) {
                                cJSON_AddStringToObject(res_root, "forward_ip", ctx->ipaddr); //转发 IP
                        } else {
                                cJSON_AddStringToObject(res_root, "forward_ip", "Not set"); //转发 IP
                        }
                        if (ctx->port > 0) {
                                snprintf(tmp_str, 40, "%d", ctx->port);
                                cJSON_AddStringToObject(res_root, "forward_port", tmp_str); //转发 端口号
                        } else {
                                cJSON_AddStringToObject(res_root, "forward_port", "-1"); //转发 端口号
                        }
                        snprintf(tmp_str, 40, "%lu", ctx->count);
                        cJSON_AddStringToObject(res_root, "forward_count", tmp_str);
                        snprintf(tmp_str, 40, "%lu", ctx->size);
                        cJSON_AddStringToObject(res_root, "forward_size", tmp_str);
		} /* End if (res_root) */
	} else {
		if (res_root) {
			snprintf(tmp_str, 40, "-1");
			cJSON_AddStringToObject(res_root, "result", tmp_str);
			snprintf(tmp_str, 40, "Unknow op:%s", cmd_op);
			cJSON_AddStringToObject(res_root, "desc", tmp_str);
		}
	} /* End check cmd_op */
res_return:
	if (res_root) {
		if (cmd_op) {
			cJSON_AddStringToObject(res_root, "op", cmd_op);
		}
		if (obj_wid) {
			cJSON_AddStringToObject(res_root, "id", obj_wid->valuestring);
		} else {
			if (pkgcap_ctx && pkgcap_ctx->wid) {
				cJSON_AddStringToObject(res_root, "id", pkgcap_ctx->wid);
			}
		}
		char *json_str = cJSON_PrintUnformatted(res_root);
		if (json_str) {
			Lzlog_debug("Send state to MQTT:%s", json_str);
			sys_debug("Send state to MQTT:%s\n", json_str);
			pkgcap_ctx->mqtt_publish(pkgcap_ctx->mosq, (void *)json_str, strlen(json_str));
                        sys_debug("free json_str\n");
			ss_free(json_str);
		}
                Lzlog_debug("cJSON_Delete res JSON obj");
                sys_debug("cJSON_Delete res JSON obj\n");
		cJSON_Delete(res_root);
	} /* End if (res_root) */
	if (root) {
		cJSON_Delete(root);
	}
	return;
}
